package test.xinhe.perf.gatling.test.ck

import java.text.SimpleDateFormat
import java.time.LocalDateTime
import java.util.Date

import io.gatling.core.Predef._
import org.xinhe.perf.gatling.sql.Predef.{sql, _}
import org.xinhe.perf.gatling.sql.db.ConnectionPool
import test.xinhe.perf.gatling.test.common.RemoteShellTool

import scala.util.Random


/**
 * @ClassName: MockData
 * @Date: 2021-4-9
 * @author: sunxinhe
 * @Version: 1.0
 * @Description:
 * 写入测试：单用户单条写入
 *
 */
class MockData extends Simulation {

  class Host(var ip: String, var port: Int, var userName: String, var password: String)

  val host = new Host("172.20.32.119", 22, "root", "rootroot")
  //  val host = new Host("192.168.12.103", 22, "root", "rootroot")

  var monitorKey = new SimpleDateFormat("yyyyMMdd").format(new Date()) + "/" + queryName() + "/" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date())

  val conn = ConnectionPool.connection

  val sqlConfig = sql.connection(conn)

  //TODO 试试这个feeder https://gatling.io/docs/2.2/session/feeder/
  val randomIdFeeder = Array(
    Map("randomDeviceId" -> randomCode(12), "randomVehicleImageId" -> randomCode(12), "randomImageId" -> randomCode(12), "randomSpeed" -> randomInt(5, 60), "randomPlateNo" -> randomInt(1000, 9999)),
    Map("randomDeviceId" -> randomCode(12), "randomVehicleImageId" -> randomCode(12), "randomImageId" -> randomCode(12), "randomSpeed" -> randomInt(5, 60), "randomPlateNo" -> randomInt(1000, 9999)),
    Map("randomDeviceId" -> randomCode(12), "randomVehicleImageId" -> randomCode(12), "randomImageId" -> randomCode(12), "randomSpeed" -> randomInt(5, 60), "randomPlateNo" -> randomInt(1000, 9999)),
    Map("randomDeviceId" -> randomCode(12), "randomVehicleImageId" -> randomCode(12), "randomImageId" -> randomCode(12), "randomSpeed" -> randomInt(5, 60), "randomPlateNo" -> randomInt(1000, 9999)),
    Map("randomDeviceId" -> randomCode(12), "randomVehicleImageId" -> randomCode(12), "randomImageId" -> randomCode(12), "randomSpeed" -> randomInt(5, 60), "randomPlateNo" -> randomInt(1000, 9999)),
    Map("randomDeviceId" -> randomCode(12), "randomVehicleImageId" -> randomCode(12), "randomImageId" -> randomCode(12), "randomSpeed" -> randomInt(5, 60), "randomPlateNo" -> randomInt(1000, 9999)),
    Map("randomDeviceId" -> randomCode(12), "randomVehicleImageId" -> randomCode(12), "randomImageId" -> randomCode(12), "randomSpeed" -> randomInt(5, 60), "randomPlateNo" -> randomInt(1000, 9999)),
    Map("randomDeviceId" -> randomCode(12), "randomVehicleImageId" -> randomCode(12), "randomImageId" -> randomCode(12), "randomSpeed" -> randomInt(5, 60), "randomPlateNo" -> randomInt(1000, 9999)),
    Map("randomDeviceId" -> randomCode(12), "randomVehicleImageId" -> randomCode(12), "randomImageId" -> randomCode(12), "randomSpeed" -> randomInt(5, 60), "randomPlateNo" -> randomInt(1000, 9999)),
    Map("randomDeviceId" -> randomCode(12), "randomVehicleImageId" -> randomCode(12), "randomImageId" -> randomCode(12), "randomSpeed" -> randomInt(5, 60), "randomPlateNo" -> randomInt(1000, 9999)),
    Map("randomDeviceId" -> randomCode(12), "randomVehicleImageId" -> randomCode(12), "randomImageId" -> randomCode(12), "randomSpeed" -> randomInt(5, 60), "randomPlateNo" -> randomInt(1000, 9999)),
    Map("randomDeviceId" -> randomCode(12), "randomVehicleImageId" -> randomCode(12), "randomImageId" -> randomCode(12), "randomSpeed" -> randomInt(5, 60), "randomPlateNo" -> randomInt(1000, 9999)),
    Map("randomDeviceId" -> randomCode(12), "randomVehicleImageId" -> randomCode(12), "randomImageId" -> randomCode(12), "randomSpeed" -> randomInt(5, 60), "randomPlateNo" -> randomInt(1000, 9999)),
    Map("randomDeviceId" -> randomCode(12), "randomVehicleImageId" -> randomCode(12), "randomImageId" -> randomCode(12), "randomSpeed" -> randomInt(5, 60), "randomPlateNo" -> randomInt(1000, 9999)),
    Map("randomDeviceId" -> randomCode(12), "randomVehicleImageId" -> randomCode(12), "randomImageId" -> randomCode(12), "randomSpeed" -> randomInt(5, 60), "randomPlateNo" -> randomInt(1000, 9999)),
    Map("randomDeviceId" -> randomCode(12), "randomVehicleImageId" -> randomCode(12), "randomImageId" -> randomCode(12), "randomSpeed" -> randomInt(5, 60), "randomPlateNo" -> randomInt(1000, 9999)),
    Map("randomDeviceId" -> randomCode(12), "randomVehicleImageId" -> randomCode(12), "randomImageId" -> randomCode(12), "randomSpeed" -> randomInt(5, 60), "randomPlateNo" -> randomInt(1000, 9999)),
    Map("randomDeviceId" -> randomCode(12), "randomVehicleImageId" -> randomCode(12), "randomImageId" -> randomCode(12), "randomSpeed" -> randomInt(5, 60), "randomPlateNo" -> randomInt(1000, 9999)),
    Map("randomDeviceId" -> randomCode(12), "randomVehicleImageId" -> randomCode(12), "randomImageId" -> randomCode(12), "randomSpeed" -> randomInt(5, 60), "randomPlateNo" -> randomInt(1000, 9999)),
    Map("randomDeviceId" -> randomCode(12), "randomVehicleImageId" -> randomCode(12), "randomImageId" -> randomCode(12), "randomSpeed" -> randomInt(5, 60), "randomPlateNo" -> randomInt(1000, 9999)),
    Map("randomDeviceId" -> randomCode(12), "randomVehicleImageId" -> randomCode(12), "randomImageId" -> randomCode(12), "randomSpeed" -> randomInt(5, 60), "randomPlateNo" -> randomInt(1000, 9999)),
    Map("randomDeviceId" -> randomCode(12), "randomVehicleImageId" -> randomCode(12), "randomImageId" -> randomCode(12), "randomSpeed" -> randomInt(5, 60), "randomPlateNo" -> randomInt(1000, 9999)),
    Map("randomDeviceId" -> randomCode(12), "randomVehicleImageId" -> randomCode(12), "randomImageId" -> randomCode(12), "randomSpeed" -> randomInt(5, 60), "randomPlateNo" -> randomInt(1000, 9999)),
    Map("randomDeviceId" -> randomCode(12), "randomVehicleImageId" -> randomCode(12), "randomImageId" -> randomCode(12), "randomSpeed" -> randomInt(5, 80), "randomPlateNo" -> randomInt(1000, 9999)),
    Map("randomDeviceId" -> randomCode(12), "randomVehicleImageId" -> randomCode(12), "randomImageId" -> randomCode(12), "randomSpeed" -> randomInt(5, 80), "randomPlateNo" -> randomInt(1000, 9999)),
    Map("randomDeviceId" -> randomCode(12), "randomVehicleImageId" -> randomCode(12), "randomImageId" -> randomCode(12), "randomSpeed" -> randomInt(5, 80), "randomPlateNo" -> randomInt(1000, 9999)),
    Map("randomDeviceId" -> randomCode(12), "randomVehicleImageId" -> randomCode(12), "randomImageId" -> randomCode(12), "randomSpeed" -> randomInt(5, 90), "randomPlateNo" -> randomInt(1000, 9999)),
    Map("randomDeviceId" -> randomCode(12), "randomVehicleImageId" -> randomCode(12), "randomImageId" -> randomCode(12), "randomSpeed" -> randomInt(5, 130), "randomPlateNo" -> randomInt(1000, 9999))
  )

  val scn =
    scenario("mock-data").repeat(repeatTimes) {
      feed(randomIdFeeder.random).exec(sql(queryName()).selectQuery(sqlQuery()))
    }

  setUp(scn.inject(atOnceUsers(userAmount())))
    .protocols(sqlConfig)


  //  before(initData())
  //  before(monitorStart())
  //  after(monitorStop())


  //region 压测配置
  def userAmount(): Int = 5

  def batchSize(): Int = 3000

  def totalSize(): Int = 600000

  def repeatTimes: Int = {
    totalSize() / (batchSize() * userAmount())
  }

  def dateString: String = "2021-01-01"

  //endregion

  def randomHourToSecond(): Long = {
    var date = new SimpleDateFormat("yyyy-MM-dd").parse(dateString)
    date.setHours(randomInt(1, 24))
    date.getTime / 1000
  }

  //region 压测SQL
  def sqlQuery(): String = {
    //TODO 生成 Insert sql
    var insertSql: StringBuffer = new StringBuffer("INSERT INTO vehicle_record_all (" +
      "`id`,\n  " +
      "`plate_type`,\n  " +
      "`plate_no`,\n  " +
      "`speed`,\n  " +
      "`appear_time`,\n  " +
      "`mark_time`,\n  " +
      "`device_id`,\n  " +
      "`vehicle_image`,\n  " +
      "`scene_image`,\n  " +
      "`vehicle_color`,\n  " +
      "`area_code`,\n  " +
      "`line_no`,\n  " +
      "`pass_time`,\n  " +
      "`plate_color`,\n  " +
      "`plate_describe`,\n  " +
      "`disappear_time`,\n  " +
      "`vehicle_class`\n) \n" +
      "VALUES")

    for (i <- 1 to batchSize()) {
      var appearTime = randomHourToSecond() + i.%(1000)
      var markTime = appearTime
      var passTime = appearTime + randomInt(3)
      var disappearTime = passTime + randomInt(3)
      var imgCode = randomCode(6)

      insertSql.append(
        "(" +
          "generateUUIDv4(), " +
          +i.%(3) + "," +
          "'浙A${randomPlateNo}" + i.%(10) + "', " +
          "plus(${randomSpeed}, " + i.%(10) + "), " +
          "" + appearTime + ", " +
          "" + markTime + ", " +
          "'${randomDeviceId}_" + 1000000 + i + "', " +
          "'http://www.gitee.com/img/${randomVehicleImageId}_" + imgCode + "', " +
          "'http://www.gitee.com/img/${randomImageId}_" + imgCode + "', " +
          +i.%(6) + "," +
          310018 + i.%(100) + "," +
          +i.%(4) + "," +
          "" + passTime + ", " +
          +i.%(3) + "," +
          +i.%(3) + "," +
          "" + disappearTime + ", " +
          +i.%(9) +
          ")"
      )

      if (i != batchSize()) {
        insertSql.append(",")
      }
    }

    println(insertSql)

    insertSql.toString


  }

  //endregion


  //region 监控工具
  def monitorStart(): Unit = {
    println("monitorStart")
    // 定义工作路径
    val localShellPath = "/data/gatling/monitor/shell/"
    val localDataPath = "/data/gatling/monitor/data/" + monitorKey + "/"
    val remoteShellPath = "/data/gatling/monitor/shell/" + monitorKey + "/"
    val remoteDataPath = "/data/gatling/monitor/data/" + monitorKey + "/"
    val rms = new RemoteShellTool(host.ip, host.port, host.userName, host.password)


    // 上传监控脚本
    println("上传监控脚本")
    println(rms.exec("mkdir -p " + remoteShellPath))
    println(rms.exec("cat << 'EOF' >> " + remoteShellPath + "monitor.sh\n\n" +
      "#!/bin/bash\n" +
      "#获取当前shell脚本路径\n" +
      "base_dir=$(cd \"$(dirname $0)\";pwd)\n" +
      "cd $base_dir\n" +
      "pwd\n" +
      "start_date=`date \"+%Y%m%d\"`\n" +
      "echo $start_date\n\n" +
      "monitor_log_path=$base_dir\"/\"$start_date\"-monitor.log\"\n\n" +
      "nohup tsar --live --cpu --mem --traffic --load --io -s user,sys,wait,util,free,used,buff,cach,total,load1,runq,plit,bytin,bytout,rqsize,rarqsz,warqsz,await  -i 1 >> $monitor_log_path & echo $! > monitor.pid\n" +
      ""))


    //    SftpUtils.upload(host.ip, host.userName, host.password, localShellPath + "monitor.sh", remoteShellPath + "monitor.sh")

    // 启动监控脚本并记录pid到文件
    println("启动监控任务")
    println(rms.exec("chmod +x " + remoteShellPath + "monitor.sh"))
    println(rms.exec("sh " + remoteShellPath + "monitor.sh"))
    println(rms.exec("cat " + remoteShellPath + "monitor.pid"))
    println(rms.exec("ps aux | grep tsar"))

  }

  def monitorStop(): Unit = {
    println("monitorStop")
    // 定义工作路径
    val localShellPath = "/data/gatling/monitor/shell/"
    val localDataPath = "/data/gatling/monitor/data/" + monitorKey + "/"
    val remoteShellPath = "/data/gatling/monitor/shell/" + monitorKey + "/"
    val remoteDataPath = "/data/gatling/monitor/data/" + monitorKey + "/"

    // 按照文件记录的pid kill监控任务
    val rms = new RemoteShellTool(host.ip, host.port, host.userName, host.password)
    println("停止监控任务")
    println(rms.exec("mkdir -p " + remoteShellPath))
    println(rms.exec("kill -9 `cat " + remoteShellPath + "monitor.pid`"))


    //TODO 下载监控数据
  }

  //endregion


  //region 数据模拟工具
  def queryName(): String = {
    "mock_data_".concat(userAmount().toString).concat("_").concat(batchSize().toString).concat("_").concat(dateString)
  }

  def randomId: String = randomCode(8)

  def randomPassTime: String = LocalDateTime.now().toString

  def randomCode: String = {
    randomCode(6)
  }

  def randomCode(size: Int): String = {
    var code = ""
    val chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
    for (i <- 1 to size) {
      code += chars charAt (Random.nextInt(chars.length))
    }
    code
  }

  def randomInt(start: Int, end: Int): Int = {
    Random.nextInt(end).%(end - start).+(start)
  }

  def randomInt(n: Int): Int = {
    Random.nextInt(n)
  }

  //endregion
}
